package com.lantosec.hmrp.modules.workflow.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.lantosec.hmrp.core.exception.AppException;
import com.lantosec.hmrp.core.util.FlowableUtils;
import com.lantosec.hmrp.modules.sysdata.entity.SysModelForm;
import com.lantosec.hmrp.modules.sysdata.entity.SysProcessForm;
import com.lantosec.hmrp.modules.sysdata.service.ISysModelFormService;
import com.lantosec.hmrp.modules.sysdata.service.ISysProcessFormService;
import com.lantosec.hmrp.modules.workflow.mapper.RepositoryMapper;
import com.lantosec.hmrp.modules.workflow.vo.FlowProcdefVO;
import com.lantosec.hmrp.core.kit.Result;
import com.lantosec.hmrp.modules.workflow.service.IWorkflowDeployService;
import com.lantosec.hmrp.modules.workflow.service.IWorkflowRepositoryService;
import com.lantosec.hmrp.modules.workflow.vo.ModelVO;
import com.lantosec.hmrp.modules.workflow.vo.SaveDeployVO;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.common.engine.impl.persistence.deploy.DeploymentCache;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.persistence.deploy.ProcessDefinitionCacheEntry;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.DeploymentBuilder;
import org.flowable.engine.repository.Model;
import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Objects;

@Service
@Primary
@Log4j2
public class WorkflowDeployServiceImpl implements IWorkflowDeployService {
    @Autowired
    private IWorkflowRepositoryService workflowRepositoryService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private ISysProcessFormService sysProcessFormService;

    @Autowired
    private ISysModelFormService sysModelFormService;

    @Autowired
    private ProcessEngineConfiguration processEngineConfiguration;

    @Autowired
    RepositoryMapper repositoryMapper;

    /**
     * 流程部署
     * @param deployVO
     * @return
     */
    @Override
    public Result<Void> deployment(SaveDeployVO deployVO) {
        /*try {
            Deployment deployment = deploymentProcessDefinitionFromModelId(deployVO.getModelId());

            FlowProcdefVO actProcdefVO = workflowRepositoryService.procdefByDeploymentId(deployment.getId());
            String uuid = UUIDUtils.get();
            SysDataProcess sysDataProcess = new SysDataProcess();
            sysDataProcess.setDataProcessId(uuid);
            sysDataProcess.setDataProcessName(actProcdefVO.getName());
            sysDataProcess.setDataProcessType(actProcdefVO.getKey());
            sysDataProcess.setStartFormId(deployVO.getStartFormId());
            sysDataProcess.setProcdefId(actProcdefVO.getId());
            sysDataProcess.setCreateTime(LocalDateTime.now());
            processService.save(sysDataProcess);

            List<SysDataProcessTask> saveList = new ArrayList<>();
            List<SaveTaskVO> taskList = deployVO.getTaskList();
            if (CollectionUtils.isNotEmpty(taskList)) {
                taskList.forEach(vo -> {
                    SysDataProcessTask task = new SysDataProcessTask();
                    task.setDataProcessId(uuid);
                    task.setProcdefId(actProcdefVO.getId());
                    task.setTaskId(vo.getTaskId());
                    task.setDataFormId(vo.getFormTableId());
                    task.setDataLayoutId(vo.getFormLayoutId());
                    task.setTaskContent(vo.getTaskContent());
                    saveList.add(task);
                });
            }
            if (saveList.size() > 0) {
                processTaskService.saveBatch(saveList);
            }

        } catch (Exception ex) {
            log.error("部署流程失败。", ex);
            return Result.fail("流程部署失败");
        }*/
        return Result.ok();
    }

    /**
     * 部署流程定义(根据modelId部署)
     *
     * @param modelId 模型ID
     * @return 部署对象
     */
    @Override
    public Deployment deploymentFromModelId(String modelId) {
        try {
            Model modelData = repositoryService.getModel(modelId);
            String processName = modelData.getName() + ".bpmn20.xml";
            String deployName = modelData.getName();
            //部署名称
            DeploymentBuilder deploymentBuilder = repositoryService.createDeployment().name(deployName).category(modelData.getCategory());
            String modelEditorSource = new String(repositoryService.getModelEditorSource(modelData.getId()), StandardCharsets.UTF_8);
            Deployment deployment = deploymentBuilder.addString(processName, modelEditorSource)
                    .deploy();    //完成部署
            // 保存与数据的关系
            FlowProcdefVO actProcdefVO = workflowRepositoryService.procdefByDeploymentId(deployment.getId());

            // 保存表单Id与工作流部署的关系
            SysModelForm modelForm = sysModelFormService.selectByModelId(modelId);
            if (!Objects.isNull(modelForm) && !Objects.isNull(actProcdefVO)) {
                sysProcessFormService.save(deployment.getId(), actProcdefVO.getId(), modelForm.getFormTableId(),modelForm.getStartLayoutId()
                        , modelForm.getStartTaskId(), modelData.getCategory(), modelData.getName(), modelForm.getProInsNameRule());
            }
            return deployment;
        } catch (Exception e) {
            log.error("部署Flowable模型错误.", e);
            throw new FlowableException("部署Flowable模型错误.", e);
        }
    }

    @Override
    public ModelVO getDeploymentInfo(String deploymentId) {
        SysProcessForm sysProcessForm = sysProcessFormService.getBaseMapper().selectOne(new QueryWrapper<SysProcessForm>()
                .eq(SysProcessForm.ColName.deployment_id.toString(), deploymentId)
        );
        if(Objects.isNull(sysProcessForm)){
            throw new AppException("查询流程部署信息失败");
        }
        String xml = repositoryMapper.queryEditorSource(deploymentId);
        xml = com.lantosec.hmrp.core.util.StringUtils.removeCustomAttrMark(xml);

        ModelVO modelVO = new ModelVO();
        modelVO.setXml(xml);
        modelVO.setFormTableId(sysProcessForm.getFormTableId());
        modelVO.setModelName(sysProcessForm.getProcessName());
        modelVO.setProcessTypeId(sysProcessForm.getProcessType());
        modelVO.setProInsNameRule(sysProcessForm.getProInsNameRule());
        modelVO.setStartLayoutId(sysProcessForm.getStartLayoutId());
        modelVO.setStartTaskId(sysProcessForm.getStartTaskId());
        modelVO.setDeploymentId(deploymentId);
        modelVO.setModelId("");
        modelVO.setDescription("");
        modelVO.setSvg("");

        return modelVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveDeploymentInfo(ModelVO modelVO) {
        if (Objects.isNull(modelVO) || StringUtils.isBlank(modelVO.getDeploymentId())) {
            throw new FlowableException("缺少必要的参数");
        }

        // 修改流程部署与表格关系表信息
        SysProcessForm sysProcessForm = sysProcessFormService.getOne(new QueryWrapper<SysProcessForm>()
                .eq(SysProcessForm.ColName.deployment_id.toString(), modelVO.getDeploymentId())
        );
        if (Objects.isNull(sysProcessForm)) {
            throw new FlowableException("查询流程部署与表格关系失败");
        }
        if (StringUtils.isNotEmpty(modelVO.getModelName())) {
            sysProcessForm.setProcessName(modelVO.getModelName());
        }
        if (StringUtils.isNotEmpty(modelVO.getProcessTypeId())) {
            sysProcessForm.setProcessType(modelVO.getProcessTypeId());
        }
        if (StringUtils.isNotEmpty(modelVO.getProInsNameRule())) {
            sysProcessForm.setProInsNameRule(modelVO.getProInsNameRule());
        }
        if (StringUtils.isNotEmpty(modelVO.getFormTableId())) {
            sysProcessForm.setFormTableId(modelVO.getFormTableId());
        }
        if (StringUtils.isNotEmpty(modelVO.getStartLayoutId())) {
            sysProcessForm.setStartLayoutId(modelVO.getStartLayoutId());
        }
        if (StringUtils.isNotEmpty(modelVO.getStartTaskId())) {
            sysProcessForm.setStartTaskId(modelVO.getStartTaskId());
        }
        sysProcessForm.setEditTime(new Date());

        sysProcessFormService.update(sysProcessForm, new UpdateWrapper<SysProcessForm>()
                .eq(SysProcessForm.ColName.deployment_id.toString(), modelVO.getDeploymentId())
        );

        // 修改部署的xml文件
        String xmlStr = com.lantosec.hmrp.core.util.StringUtils.addCustomAttrMark(modelVO.getXml());
        repositoryMapper.updateEditorSource(xmlStr, modelVO.getDeploymentId());

        // 删除部署文件的缓存
        this.deleteCache(sysProcessForm.getProcdefId());
    }

    @Override
    public Boolean deleteCache(String processDefinitionId) {
        ProcessEngineConfigurationImpl configure = (ProcessEngineConfigurationImpl)processEngineConfiguration;
        DeploymentCache<ProcessDefinitionCacheEntry> processDefinitionCache = configure.getDeploymentManager().getProcessDefinitionCache();
        processDefinitionCache.remove(processDefinitionId);
        return Boolean.TRUE;
    }
}
